package org.jeecg.modules.flowable.service.action.impl;

import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.task.api.Task;
import org.jeecg.modules.flowable.common.util.validation.AssertValid;
import org.jeecg.modules.flowable.common.util.validation.MustParamValidation;
import org.jeecg.modules.flowable.exception.ModuleFlowableException;
import org.jeecg.modules.flowable.mapper.TActMatterInstMapper;
import org.jeecg.modules.flowable.mapper.TActTheendMapper;
import org.jeecg.modules.flowable.service.FlowProcService;
import org.jeecg.modules.flowable.service.FlowableService;
import org.jeecg.modules.flowable.service.action.ActionBody;
import org.jeecg.modules.flowable.service.action.ActionExec;
import org.jeecg.modules.flowable.util.FlowableUtil;
import org.jeecg.modules.flowable.system.core.SystemUser;
import org.jeecg.modules.flowable.system.etc.SystemUserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Title: 流程回退 <br>
 * Desc:  <br>
 * Date: 6/26/22 10:03 AM <br>
 * Company: 联通（辽宁）产业互联网有限公司 <br>
 *
 * @author zxd
 * @version 1.0.0
 */
@Service("Fallback")
@Slf4j
public class Fallback implements ActionExec {
    @Autowired
    private FlowProcService flowProcService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private TActTheendMapper tActTheendMapper;

    @Autowired
    private TActMatterInstMapper tActMatterInstMapper;

    @Autowired
    private FlowableService flowableService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deal(ActionBody argActionBody,String argActionFunname,String argActionFuncode) {
        MustParamValidation.mustValidation(argActionBody.getMatterInstId(),argActionBody.getTaskId());
        SystemUser loginUser = SystemUserUtil.getSystemUser();
        // 第一步：保存
        flowProcService.save(argActionBody.getMatterInstId(),argActionBody.getTaskId(),argActionBody.getAttType(),argActionBody.getAttDesc(),argActionBody.getFormData(),argActionBody.getAttrList(),argActionFunname,argActionFuncode,argActionBody.getFormContent());

        // 第二步：查询BPMN模型
        List<Task> list = taskService.createTaskQuery().taskId(argActionBody.getTaskId()).list();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().processDefinitionId(list.get(0).getProcessDefinitionId()).orderByProcessDefinitionVersion().desc();

        List<ProcessDefinition> list1 = processDefinitionQuery.list();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(list1.get(0).getId());
        List<Process> processes = bpmnModel.getProcesses();
        Process process = processes.get(0);
        Collection<FlowElement> flowElements = process.getFlowElements();

        String currTaskKey = list.get(0).getTaskDefinitionKey();
        // 得到回退的上一级用户任务列表
        List<UserTask> targetUserTask = FlowableUtil.getParentUserTaskList(flowElements, currTaskKey,null);
        // 过滤目标任务列表，从历史流程记录中去掉没走过的用户任务
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select RES.ACT_ID_ AS ACT_ID from ACT_HI_ACTINST RES WHERE RES.PROC_INST_ID_ = '" + list.get(0).getProcessInstanceId() + "' order by START_TIME_ asc");
        for (int i=0;i<targetUserTask.size();i++) {
            UserTask userTask = targetUserTask.get(i);
            Boolean isExists = false;
            f:for (Map<String, Object> map : maps) {
                if(map.get("ACT_ID").toString().trim().equals(userTask.getId())) {
                    isExists = true;
                    break f;
                }
            }
            if(!isExists) {
                targetUserTask.remove(i);
                i--;
            }
        }
        // 得到当前任务执行流的用户任务
        List<Execution> list2 = runtimeService.createExecutionQuery().parentId(list.get(0).getProcessInstanceId()).list();
        List<String> sourceTaskId = null;
        List<UserTask> tiedForUserTaskList = FlowableUtil.getTiedForUserTaskList(flowElements, currTaskKey,null);

        if(AssertValid.isEmpty(tiedForUserTaskList)) {
            // 当返回数据为空的情况，说明当前任务的前一个节点是用户任务，将原节点置成一个。
            sourceTaskId = list2.stream().filter(s -> s.getActivityId().equals(currTaskKey)).map(Execution::getId).collect(Collectors.toList());
        } else {
            // 把当前任务扔到tiedForUserTaskList里，否则同级的任务中没有当前任务
            UserTask userTask1 = FlowableUtil.queryUserTesk(flowElements, currTaskKey);
            tiedForUserTaskList.add(userTask1);
            // 当返回数据为多条的情况，说明当前任务的另一个分支有会签，则取另一个分支下的所有用户任务，和当前执行流取交集。
            for(int i=0;i<list2.size();i++) {
                Boolean isExists = false;
                f:for (UserTask userTask : tiedForUserTaskList) {
                    if(userTask.getId().equals(list2.get(i).getActivityId())) {
                        isExists = true;
                        break f;
                    }
                }
                if(!isExists) {
                    list2.remove(i);
                    i--;
                }
            }
            // 重新赋值
            sourceTaskId = list2.stream().map(s -> {
                return s.getId();
            }).collect(Collectors.toList());
        }

        if(sourceTaskId.size()>1 && targetUserTask.size()>1) {
            throw new ModuleFlowableException("因流任务关系复杂，暂时不支持多对多任务节点回退");
        }
        if(sourceTaskId.size()>1 && targetUserTask.size()==1) {
            runtimeService.createChangeActivityStateBuilder().processInstanceId(list.get(0).getProcessInstanceId()).moveExecutionsToSingleActivityId(sourceTaskId,targetUserTask.get(0).getId()).changeState();
        }
        if(sourceTaskId.size()==1 && targetUserTask.size()>1) {
            List<String> target = targetUserTask.stream().map(s -> {
                return s.getId();
            }).collect(Collectors.toList());
            runtimeService.createChangeActivityStateBuilder().processInstanceId(list.get(0).getProcessInstanceId()).moveSingleExecutionToActivityIds(sourceTaskId.get(0),target).changeState();
        }
        if(sourceTaskId.size()==1 && targetUserTask.size()==1) {
            runtimeService.createChangeActivityStateBuilder().processInstanceId(list.get(0).getProcessInstanceId()).moveExecutionToActivityId(sourceTaskId.get(0),targetUserTask.get(0).getId()).changeState();
        }
        if(sourceTaskId.size()<1 ) {
            throw new ModuleFlowableException("当前任务节点不存在，回退失败");
        }
        if(targetUserTask.size()==0) {
            throw new ModuleFlowableException("第一个用户任务节点不能发起回退");
        }
        return true;
    }
}